package cn.tuling.ribbon.rules;

import cn.tuling.ribbon.balancer.WeightedBalancer;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 同集群优先负载均衡算法
 */
@Slf4j
public class SameClusterPriorityRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties discoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
        // nothing
    }

    @Override
    public Server choose(Object key) {
        try {
            // 1. 获取当前服务所在集群
            String currentClusterName = discoveryProperties.getClusterName();

            // 2. 获取负载均衡对象
            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) getLoadBalancer();

            // 3. 获取当前调用的微服务名称
            String invokedServiceName = loadBalancer.getName();

            // 4. 获取nacos client的服务注册发现组件的api
            NamingService namingService = discoveryProperties.namingServiceInstance();

            // 5. 获取所有的服务实例
            List<Instance> allInstances = namingService.getAllInstances(invokedServiceName);

            // 6. 过滤筛选同集群下的所有实例
            List<Instance> theSameClusterNameInstList = new ArrayList<>();
            for (Instance instance : allInstances) {
                if (StringUtils.endsWithIgnoreCase(instance.getClusterName(), currentClusterName)) {
                    theSameClusterNameInstList.add(instance);
                }
            }

            // 7. 选择一个合适的实例调用
            Instance toBeChooseInstance;
            if (theSameClusterNameInstList.isEmpty()) {
                toBeChooseInstance = WeightedBalancer.chooseInstanceByRandomWeight(allInstances);
                log.info("发生跨集群调用--->当前微服务所在集群:{},被调用微服务所在集群:{},Host:{},Port:{}",
                        currentClusterName, toBeChooseInstance.getClusterName(), toBeChooseInstance.getIp(), toBeChooseInstance.getPort());
            } else {
                toBeChooseInstance = WeightedBalancer.chooseInstanceByRandomWeight(theSameClusterNameInstList);
                log.info("同集群调用--->当前微服务所在集群:{},被调用微服务所在集群:{},Host:{},Port:{}",
                        currentClusterName, toBeChooseInstance.getClusterName(), toBeChooseInstance.getIp(), toBeChooseInstance.getPort());
            }

            return new NacosServer(toBeChooseInstance);
        } catch (NacosException e) {
            log.error("同集群优先&权重负载均衡算法选择异常:{}", e.toString());
        }
        return null;
    }
}
